import * as util from "./utils";
import * as graphicUtil from "./GraphicUtil";

// 配置文件
const styleConfig = {
    pin:{
        color:{
            t:"#b34141",
            ts_t:"#990066",
            ts_b:"#990066",
            tp_t:"#CCCCFF",
            tp_b:"#CCCCFF",
            
            i:"#99CCCC",
            is_t:"#990066",
            is_b:"#990066",
            ip_t:"#CCCCFF",
            ip_b:"#CCCCFF",
            
            b:"#336699",
            bs_t:"#990066",
            bs_b:"#990066",
            bp_t:"#CCCCFF",
            bp_b:"#CCCCFF",
            
            drill:"#CCCCCC",//过孔颜色
            contour:"#99CCCC",   //pin描边颜色 
        }
    },
    layer:{
        st:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        sb:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        at:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        ab:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        sm_t:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        sm_b:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        et:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        eb:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        bt:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        bb:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        pt:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        },
        pb:{
            text:{
                color_text:"black",//文字颜色
                color_border:"red",//文字范围
                typeface:"微软雅黑",//字体
                text_size:"10",//字号
            },
            path:{
                color_line:"#1a2273",//线颜色
                line_width:1,//线宽
            },
            shape:{
                color_fill:"green",//铜皮填充颜色
                color_out:"#83b31e",//铜皮镂空部分颜色 
                color_line:"while",//描边颜色
                line_width:1,//线宽
            },  
        }
    },
    color_origin:"#a4bfa4",     //原点颜色
    typeface:"微软雅黑",            //全局字体 
    text_size:"20px",           //全局字号
    line_width:1,               //线宽
    txt_color:"black",
    
    highlight_color:"#ffbc00bd",  //强调的颜色
    highlight_scope:10,           //强调的范围
    grid_color:"#c0c0c0",       //格点颜色
}

function makeMap(str,isLowerCase){
    let map = {};
    let arr = str.split(",");
    arr.forEach(item=>{
        map[item] = true;
    });
    return isLowerCase?(str)=>map[str.toUpperCase()]:(str)=>map[str];
}

// 判断单位是否合法
var checkUnits = makeMap("mm,mils");

// 判断图形层是否合法
var checkLayer = makeMap("st,sb,at,ab,sm_t,sm_b,et,eb,bt,bb,pt,pb");

// 判断pin的图层是否合法
var checkPinLayer = makeMap("b,bs_t,bs_b,bp_t,bp_b,t,ts_t,ts_b,tp_t,tp_b,i,is_t,is_b,ip_t,ip_b,drill");

class Encapsulation{
    id = "";

    name = "unnamed";

    deviceInfo = {
        name:"",
        layer:"",
        range:{
            x:[0,0],
            y:[0,0]
        },

        // 封装的位置
        x: 0,
        y: 0,

        // 旋转角度
        rotate:0
    }

    type = "PACKAGE"

    units = "mm";

    _history = [];

    rawData = {};

    // 图形编号集合
    #numberList = [];

    // 图形集合
    /**
     * @type {BaseImage []}
     */
    diagramList = [];

    // Pad集合
    /**
     * @type {EPad []}
     */
    pads = [];

    range = {
        x: [0,0],
        y: [0,0]
    }

    // 显示的canvas
    constructor(encaData){
        if(util && util.uuidv4){
            this.id = util?.uuidv4();
        }
        if(encaData){
            this.setEncaData(encaData);
        }
    }

    setEncaData(encaData){
        if(!encaData || util.getRawType(encaData) !== "Object" || util.getRawType(encaData.img_data) !== "Object"){
            return;
        }else{
            this.rawData = encaData;

            this.units = encaData.units || "mm";

            try{
                this.transformEncaData(encaData);
                this.range = this.getRange();
            }catch(e){
                console.error(encaData,"解析出错了",e);
            }
    
        }
    }

    transformEncaData(encaData){
        this.name = encaData.encapsulation_name || "unnamed";
        
        let imgData = encaData.img_data;
        // 将数据进行遍历
        let bigLayerList = ["ss","asm","sm","e","b","p"];
        let layerList = {ss:["st","sb"],asm:["at","ab"],sm:["sm_t","sm_b"],e:["et","eb"],b:["bt","bb"],p:["pt","pb"]};

        // 处理pad

        // pad原始id与pad对应
        let idToPad = {}

        imgData.pads.forEach(pad=>{
            let padInstance = new EPad(this.units,pad);
            padInstance.setEncapsulation(this);
            idToPad[pad.id] = padInstance;
            this.pads.push(padInstance);
        });

        imgData.pins.forEach(pin=>{
            let pinInstance = new EPin(this.units,pin);
            pinInstance.setPad(idToPad[pin.pin_padid]);
            pinInstance.setEncapsulation(this);
            this.diagramList.push(pinInstance);
        });

        bigLayerList.forEach((bigLayer)=>{
            let smallLayerList = layerList[bigLayer];
            if(!imgData[bigLayer]){
                return;
            }
            var bigLayerData = imgData[bigLayer];
            if(!bigLayerData){
                return;
            }
            smallLayerList.forEach((smallLayer)=>{
                var smallLayerData = bigLayerData[smallLayer];
                if(!smallLayerData){
                    return;
                }
                if(util.getRawType(smallLayerData.texts) === "Array"){
                    smallLayerData.texts.forEach(text=>{
                        let graphicInstance = new EText(this.units,smallLayer,text);
                        graphicInstance.setEncapsulation(this);
                        this.diagramList.push(graphicInstance);
                    });
                }

                if(util.getRawType(smallLayerData.paths) === "Array"){
                    smallLayerData.paths.forEach(path=>{
                        let graphicInstance = EPath.create(path,this.units,smallLayer);
                        graphicInstance.setEncapsulation(this);
                        this.diagramList.push(graphicInstance);
                    });
                }

                if(util.getRawType(smallLayerData.shapes) === "Array"){
                    smallLayerData.shapes.forEach(shape=>{
                        let graphicInstance = new EShape(this.units,smallLayer,shape);
                        graphicInstance.setEncapsulation(this);
                        this.diagramList.push(graphicInstance);
                    });
                }
            });
        });
    }

    // 恢复
    redo(){
        
    }

    // 撤销
    undo(){

    }

    // 获取范围
    getRange(){
        let range = null;
        this.diagramList.forEach(img=>{
            var dirRange = img.getRange();
            if(!dirRange){
                throw img
            }
            range = graphicUtil.compareRange(range,dirRange);
        });
        if(!range){
            range = {
                x:[0,0],
                y:[0,0]
            }
        }
        return range;
    }

    // 获取原始数据
    getRawData(){
        let smallToBig = {st:"ss",sb:"ss",at:"asm",ab:"asm",sm_t:"sm",sm_b:"sm",et:"e",eb:"e",bt:"b",bb:"b",pt:"p",pb:"p"};
        let bigLayerList = ["ss","asm","sm","e","b","p"];
        let layerList = {ss:["st","sb"],asm:["at","ab"],sm:["sm_t","sm_b"],e:["et","eb"],b:["bt","bb"],p:["pt","pb"]};

        let encaData = {
            img_data:{
                pins:[],
                pads:[]
            },
            units: this.units
        }

        bigLayerList.forEach(bLayer=>{
            encaData.img_data[bLayer] = {};
            layerList[bLayer].forEach(layer=>{
                encaData.img_data[bLayer][layer] = {
                    texts:[],
                    paths:[],
                    shapes:[]
                }
            })
        });

        this.diagramList.forEach(graphic=>{
            if(graphic.type == "pins"){
                encaData.img_data.pins.push(graphic.getRawData());
            }else{
                encaData.img_data[smallToBig[graphic.layer]][graphic.layer][graphic.type].push(graphic.getRawData());
            }
        });

        this.pads.forEach(pad=>{
            encaData.img_data.pads.push(pad.getRawData());
        });

        return encaData;
    }

    touch(point){
        this.diagramList.forEach(graphic=>{
            graphic.touch(point);
        });
    }

    createGraphic(option){
        if(option.type == "PATH"){
            if(option.form == "LINE"){
                let line = new ELine(this.units,option.layer);
                line.setEncapsulation(this);
                return line;
            }
        }
    }
}

class BaseImage{
    // 图形在封装中的唯一id
    id = 0;

    type = "base";

    units = "mm";

    /**
     * @type {Encapsulation}
     */
    encapsulation = null;

    // 图形编辑的历史记录
    _editHistory = [];

    constructor(units){
        if(!checkUnits(units)){
            throw "units 不是 mm 或 mils",units,this;
        }
        this.units = units;
        // 生成图形id
        this.id = util?.uuidv4();
    }

    // 转换为原始封装数据
    getRawData(){}

    // 转换为绘图数据
    getDrawData(scale){
    }

    // 获取图形的范围
    /**
     * @returns {{x:[],y:[]}}
    */
    getRange(){

    }

    // 获取图形绘制范围
    /**
     * @returns {{x:[],y:[]}}
     */
    getDrawRange(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
        let range = this.getRange();
        if(!range){
            console.log(this);
        }
        range.x[0] *= scale;
        range.x[1] *= scale;
        let maxY = range.y[0] * -scale;
        let minY = range.y[1] * -scale;
        range.y[0] = minY;
        range.y[1] = maxY;
        return range;
    }

    // 获取图形的大小
    getSize(){}

    // 获取图形的正中心点
    /**
     * @returns {{x:number,y:number}}
     */
    getCenter(){}

    // 判断点是否在图形内
    inGraph(point){}

    // 更新图形数据
    update(){}

    // 旋转图形
    setRotate(){}

    // 移动图形
    /**
     * 
     * @param {{x:number,y:number}} offset 
     */
    move(offset){}

    // 切换单位制
    changeUnits(){}

    // 恢复编辑
    redo(){}

    // 撤销编辑
    undo(){}

    // 设置原始数据
    setRawData(data){
        if(util.getRawType(data) != "Object"){
            throw "TypeError:转换" + this.type + "数据失败，需要传入Object，你传入了",util.getRawType(arcData);
            return false;
        }
        return true;
    }

    // 设置所属封装
    setEncapsulation(encaInstance){
        this.encapsulation = encaInstance;
    }

    // 图形是否在视图内
    inView(canvasOrigin,scale,width,height,rotate){
        let drawRange = this.getDrawRange(scale);
        if(isNaN(drawRange.x[0])){
            console.error("范围计算有误",this)
        }
        if(rotate){
            // drawRange.x[0] += center.x;
            // drawRange.x[1] += center.x;
            // drawRange.y[0] += center.y;
            // drawRange.y[1] += center.y;
            drawRange = graphicUtil.rotateRange(drawRange,rotate,{x:0,y:0});
            // console.log(drawRange)
        }

        // console.log(canvasOrigin)
        // return true;
        var myRect = {
            x: drawRange.x[0] + canvasOrigin.x,
            y: drawRange.y[0] + canvasOrigin.y,
            width: Math.abs(drawRange.x[0] - drawRange.x[1]),
            height: Math.abs(drawRange.y[0] - drawRange.y[1])
        }
        let status = graphicUtil.getCrossRect(myRect,{
            x:0,
            y:0,
            width,
            height
        });
        // return true;
        return status;
    }

    // 图形是否被选中
    inSelect(point){
        return false;
    }

    touch(point){
        let range = this.getRange();
        if(point.x > range.x[0] && point.x < range.x[1] && point.y > range.y[0] && point.y < range.y[1]){
            this.isTouch = true;
            return true;
        }
    }

    static rotateRange(range,center,rotate){
        let points = [
            [range.x[1],range.y[0]],
            [range.x[1],range.y[1]],
            [range.x[0],range.y[0]],
            [range.x[0],range.y[1]]
        ];

        points = graphicUtil.rotatePoints(points,center,rotate);

        var maxX = points[0][0],maxY = points[0][1],minX = points[0][0],minY = points[0][1];
        points.forEach(point=>{
            if(maxX < point[0]){
                maxX = point[0];
            }
            if(maxY < point[1]){
                maxY = point[1];
            }
            if(minX > point[0]){
                minX = point[0];
            }
            if(minY > point[1]){
                minY = point[1];
            }
        });
        range = {
            x:[minX, maxX],
            y:[minY, maxY]
        }
        return range;
    }
}

class EncaImage extends BaseImage{
    strokeStyle = "";
    layer = "";
}

class Text extends BaseImage{
    // 文字内容
    content = "";
    // 中心坐标
    x = 0;
    y = 0;
    // 字体宽度
    w = 0;
    // 字体高度
    h = 0;
    // 字号
    fontSize = 10;
    // 旋转角度
    rotateAngle = 0;
    // 字体类型
    form = "TEXT";

    constructor(units,data){
        super(units);
        this.type = "texts";
        if(data){
            this.setRawData(data);
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.x = data.x || 0;
        this.y = data.y || 0;
        this.content = data.content || "";
        this.rotateAngle = data.rotate || 0;
        this.fontSize = data.textblock;
        // 计算字体大小
        let textSize = this.getSize();
        this.w = textSize.w;
        this.h = textSize.h;
    }

    rotate(rotate,center){
        if(!center){
            this.rotateAngle = rotate;
        }else{
            var rotatePoint = graphicUtil.rotatePoint({x:this.x, y:this.y},center,rotate);
            this.x = rotatePoint.x;
            this.y = rotatePoint.y;
            this.rotateAngle += rotate;
        }
    }

    getRawData(){
        return {
            rotate: this.rotateAngle,
            name: this.form,
            x: this.x,
            y: this.y,
            textheight: this.w,
            textwidth: this.h,
            content: this.content,
            textblock: this.fontSize
        }
    }

    getDrawData(scale){
        return {
            id: this.id,
            layer: this.layer,
            type: this.type,
            form: this.form,
            fillStyle:this.fillStyle,
            alpha:this.alpha,
            data: {
                rotate: this.rotateAngle,
                name: this.form,
                x: this.x * scale,
                y: - this.y * scale,
                textheight: this.w * scale,
                textwidth: this.h * scale,
                content: this.content,
                textblock: this.fontSize * scale
            }
        }
    }

    getRange(){
        return {
            x:[this.x - this.w / 2, this.x + this.w / 2],
            y:[this.y - this.h / 2, this.y + this.h / 2]
        }
    }

    getSize(){
        return {
            w: this.content.length * this.fontSize / 2,
            h: this.fontSize
        }
    }
}

class EText extends Text{ 
    layer = "st";

    fillStyle = "#000000";

    constructor(units,layer,data){
        super(units);
        this.setLayer(layer);
        this.fillStyle = styleConfig.layer[this.layer].text.color_text;
        this.type = "texts";
        if(data){
            this.setRawData(data);
        }
    }
    
    setLayer(layer){
        if(!checkLayer(layer)){
            throw "传入的层有误！"
        }
        this.layer = layer;
    }

    getDrawData(scale){
        let drawData = super.getDrawData(scale);
        drawData.fillStyle = this.fillStyle;
        return drawData;
    }
}

class EPath extends BaseImage{
    constructor(){
        this.type = "path";
    }

    static create(lineData,units,layer){
        if(util.getRawType(lineData) !== "Object"){
            throw "路径数据有误" + lineData;
        }
        if(util.getRawType(lineData.name) !== "String"){
            throw "路径数据的name有误!" + lineData;
        }
        let form = lineData.name.toUpperCase();
        if(form === "LINE"){
            return new ELine(units,layer,lineData);
        }
        if(form === "ARC"){
            return new EArc(units,layer,lineData);
        }
    }
}

class BasePath extends BaseImage{

    /**
     * @type {BaseImage []}
     */
    path = [];

    constructor(units,data){
        super(units);
        if(data){
            this.setRawData(data);
        }
    }

    setRawData(data){
        if(!(data instanceof Array)){
            throw "TypeError: 需要一个数组!";
        }
        data.forEach(lineData=>{
            this.path.push(BasePath.create(lineData,this.units));
        });
    }

    getRawData(){
        let paths = [];
        this.path.forEach(line=>{
            paths.push(line.getRawData());
        });
        return {path:paths,form:"PATH"};
    }

    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
        let draw = [];
        this.path.forEach(base=>{
            draw.push(base.getDrawData(scale));
        });
        return draw;
    }

    getRange(){
        var range = null;

        this.path.forEach(line=>{
            let lineRange = line.getRange();
            range = compareRange(range,lineRange);
        });

        return range;

        function compareRange(range,toRange){
            if(!toRange){
                return {
                    x:[
                        range.x[0],
                        range.x[1]
                    ],
                    y:[
                        range.y[0],
                        range.y[1]
                    ]
                };
            }
            if(!range){
                return {
                    x:[
                        toRange.x[0],
                        toRange.x[1]
                    ],
                    y:[
                        toRange.y[0],
                        toRange.y[1]
                    ]
                };
            }
            var compare = {
                x:[0,0],
                y:[0,0]
            }
            compare.x[0] = toRange.x[0] < range.x[0] ? toRange.x[0] : range.x[0];
            compare.x[1] = toRange.x[1] > range.x[1] ? toRange.x[1] : range.x[1];
            compare.y[0] = toRange.y[0] < range.y[0] ? toRange.y[0] : range.y[0];
            compare.y[1] = toRange.y[1] > range.y[1] ? toRange.y[1] : range.y[1];
            return compare;
        }
    }

    static create(lineData,units){
        if(util.getRawType(lineData) !== "Object"){
            throw "路径数据有误" + lineData;
        }
        if(util.getRawType(lineData.name) !== "String"){
            throw "路径数据的name有误!" + lineData;
        }
        let form = lineData.name.toUpperCase();
        if(form === "LINE"){
            return new BaseLine(units,lineData);
        }
        if(form === "ARC"){
            return new BaseArc(units,lineData);
        }
    }
}

class BaseLine extends BaseImage{
    startX = 0;
    startY = 0;
    endX = 0;
    endY = 0;
    constructor(units,lineData){
        super(units);

        this.type = "paths";
        this.form = "LINE";
        if(lineData){
            this.setRawData(lineData);
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.startX = data.st_x || 0;
        this.startY = data.st_y || 0;
        this.endX = data.sp_x || 0;
        this.endY = data.sp_y || 0;
    }

    getRawData(){
        return {
            st_x: this.startX,
            st_y: this.startY,
            sp_x: this.endX,
            sp_y: this.endY,
            name: this.form
        }
    }

    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }

        return {
            st_x: this.startX * scale,
            st_y: this.startY * - scale,
            sp_x: this.endX * scale,
            sp_y: this.endY * - scale,
            name: this.form
        }
    }

    getRange(){
        var maxX = this.startX > this.endX ? this.startX : this.endX,
            minX = this.startX > this.endX ? this.endX : this.startX,
            maxY = this.startY > this.endY ? this.startY : this.endY,
            minY = this.startY > this.endY ? this.endY : this.startY;

        return {
            x: [minX, maxX],
            y: [minY, maxY]
        }
    }

    rotate(rotate,center){
        if(!center){
            center = {
                x: (this.startX + this.endX) / 2,
                y: (this.startY + this.endY) / 2
            }
        }
        let start = graphicUtil.rotatePoint({
            x: this.startX,
            y: this.startY
        },center,rotate);

        let end = graphicUtil.rotatePoint({
            x: this.endX,
            y: this.endY
        },center,rotate);

        this.startX = start.x;
        this.startY = start.y;
        this.endX = end.x;
        this.endY = end.y;
    }

    getCenter(){
        return {
            x : (this.startX + this.endX) / 2,
            y : (this.startY + this.endY) / 2
        }
    }

    move(offset){
        this.startX += offset.x;
        this.startY += offset.y;
        this.endX += offset.x;
        this.endY += offset.y;
    }

    static create(lineData,units){
        let baseLine = new BaseLine(units);
        if(util.getRawType(lineData) != "Object"){
            console.error("TypeError:转换" + baseLine.type + "数据失败，需要传入Object，你传入了" + util.getRawType(lineData));
            return baseLine;
        }
        baseLine.startX = lineData.st_x || 0;
        baseLine.startY = lineData.st_y || 0;
        baseLine.endX = lineData.sp_x || 0;
        baseLine.endY = lineData.sp_y || 0;
        return baseLine;
    }
}

class BaseArc extends BaseImage{
    // 起始点
    startX = 0;
    startY = 0;
    // 终点
    endX = 0;
    endY = 0;
    // 圆心
    cenX = 0;
    cenY = 0;
    // 方向，true为顺时针，false为逆时针
    direction = true;
    // 半径
    r = 0;

    form = "ARC";

    type = "paths";

    constructor(units,arcData){
        super(units);

        if(arcData){
            this.setRawData(arcData);
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.startX = data.st_x || 0;
        this.startY = data.st_y || 0;
        this.endX = data.sp_x || 0;
        this.endY = data.sp_y || 0;
        this.cenX = data.o_x || 0;
        this.cenY = data.o_y || 0;
        this.direction = data.arc_r == "nil";
        this.r = data.r;
    }

    getRawData(){
        return {
            st_x: this.startX,
            st_y: this.startY,
            sp_x: this.endX,
            sp_y: this.endY,
            width: this.lineWidth,
            name: this.form,
            o_x: this.cenX,
            o_y: this.cenY,
            arc_r: this.direction ? "t" : "nil",
            r: this.r
        }
    }
    
    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
        
        return {
            st_x: this.startX * scale,
            st_y: -this.startY * scale,
            sp_x: this.endX * scale,
            sp_y: -this.endY * scale,
            width: this.lineWidth * scale,
            name: this.form,
            o_x: this.cenX * scale,
            o_y: -this.cenY * scale,
            arc_r: this.direction,
            r: this.r * scale
        }
    }

    getRange(){
        if(this.endX == this.startX && this.endY == this.startY){
            return {
                x:[this.cenX - this.r, this.cenX + this.r],
                y:[this.cenY - this.r, this.cenY + this.r]
            }
        }
        let isRound = false;
        let maxX = 0,minX = 0,minY = 0,maxY = 0;
        if(this.startX > this.endX){
            maxX = this.startX;
            minX = this.endX;
            if(this.direction == "t"){
                maxY = -(-this.cenY + this.r);
                minY = this.startY;
                if(-this.startY > -this.endY){
                    minY = this.endY;
                    minX = this.cenX - this.r;
                }
                else if(-this.startY < -this.endY){
                    minY = this.startY;
                    maxX = this.cenX + this.r;
                }
            }else{
                maxY = this.startY;
                minY = -(-this.cenY - this.r);
                if(-this.startY > -this.endY){
                    maxY = this.startY;
                    maxX = this.cenX + this.r;
                }
                else if(-this.startY < -this.endY){
                    maxY = this.endY;
                    minX = this.cenX - this.r;
                }
            }
        }
        else if(this.startX < this.endX){
            maxX = this.endX;
            minX = this.startX;
            if(this.direction == "t"){
                minY = -(-this.cenY - this.r);
                maxY = this.startY;
                if(-this.startY < -this.endY){
                    maxY = this.endY;
                    maxX = this.cenX + this.r;
                }
                else if(-this.startY > -this.endY){
                    maxY = this.startY;
                    minX = this.cenX - this.r;
                }
            }else{
                maxY = -(-this.cenY + this.r);
                minY = this.startY;
                if(-this.startY > -this.endY){
                    minY = this.endY;
                    maxX = this.cenX + this.r;
                }
                else if(-this.startY < -this.endY){
                    minY = this.startY;
                    minX = this.cenX - this.r;
                }
            }
        }
        else{
            if(this.startY != this.endY){
                if(this.direction == "t"){
                    if(-this.startY < -this.endY){
                        maxY = this.endY;
                        minY = this.startY;
                        maxX = this.cenX + this.r;
                        minX = this.cenX;
                    }
                    else if(-this.startY > -this.endY){
                        maxY = this.startY;
                        minY = this.endY;
                        maxX = this.cenX;
                        minX = this.cenX - this.r;
                    }
                }else{
                    if(-this.startY > -this.endY){
                        maxY = this.startY;
                        minY = this.endY;
                        maxX = this.cenX + this.r;
                        minX = this.cenX;
                    }
                    else if(-this.startY < -this.endY){
                        maxY = this.endY;
                        minY = this.startY;
                        maxX = this.cenX;
                        minX = this.cenX - this.r;
                    }
                }
            }
            else{
                isRound = true;
                maxY = this.cenY + this.r;
                minY = this.cenY - this.r;
                maxX = this.cenX + this.r;
                minX = this.cenX - this.r;
            }
        }
        if(isRound){
            return {
                x:[minX,maxX],
                y:[minY,maxY]
            };
        }else{
            return {
                x:[minX,maxX],
                y:[maxY,minY]
            };
        }
    }

    getCenter(){
        return {
            x : (this.startX + this.endX) / 2,
            y : (this.startY + this.endY) / 2
        }
    }

    rotate(rotate,center){
        var updateCenter = true;
        if(!center){
            updateCenter = false;
            center = {
                x: this.cenX,
                y: this.cenY
            }
        }
        var start = graphicUtil.rotatePoint({
            x: this.startX,
            y: this.startY
        },center,rotate);

        var end = graphicUtil.rotatePoint({
            x: this.endX,
            y: this.endY
        },center,rotate);

        if(updateCenter){
            var cen = graphicUtil.rotatePoint({
                x: this.cenX,
                y: this.cenY
            },center,rotate);
            this.cenX = cen.x;
            this.cenY = cen.y;
        }

        this.startX = start.x;
        this.startY = start.y;
        this.endX = end.x;
        this.endY = end.y;
    }

    move(offset){
        this.startX += offset.x;
        this.startY += offset.y;
        this.endX += offset.x;
        this.endY += offset.y;
        this.cenX += offset.x;
        this.cenY += offset.y;
    }
}

class BaseRect extends BaseImage{
    width = 0;

    height = 0;

    x = 0;

    y = 0;

    rotate = 0;

    constructor(units,rectData){
        super(units);
        if(rectData){
            this.setRawData(rectData);
        }
    }

    setRawData(data){
        this.width = data.w || 0;
        this.height = data.h || 0;
        this.x = data.x || 0;
        this.y = data.y || 0;
        // this.lineWidth = data.width;
    }

    getRawData(){
        return {
            w: this.width,
            h: this.height,
            x: this.x,
            y: this.y,
            rotate: this.rotate,
            form: "S"
        }
    }

    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
        return {
            w: Math.round(this.width * scale),
            h: Math.round(this.height * scale),
            x: Math.round(this.x * scale),
            y: Math.round(this.y * - scale),
            rotate: this.rotate,
            form: "S"
            // width: this.lineWidth * scale
        }
    }

    getRange(){
        let range = {
            x: [this.x - this.width / 2, this.x + this.width / 2],
            y: [this.y - this.height / 2, this.y + this.height / 2]
        }

        if(this.rotate){
            range = BaseImage.rotateRange(range,{x: this.x, y: this.y}, this.rotate);
        }

        return range;
    }
}

class BaseCircle extends BaseImage{
    r = 0;

    x = 0;
    
    y = 0;

    type = "C";

    constructor(units,data){
        super(units);
        if(data){
            this.setRawData(data);
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.r = data.r || data.w / 2;
        this.x = data.x || 0;
        this.y = data.y || 0;
    }

    getRawData(){
        return {
            w: this.r * 2,
            h: this.r * 2,
            x: this.x,
            y: this.y,
            r: this.r,
            form: "C"
        }
    }

    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
        return {
            x: Math.round(this.x * scale),
            y: Math.round(this.y * -scale),
            w: Math.round(this.r * 2 * scale),
            h: Math.round(this.r * 2 * scale),
            r: Math.round(this.r * scale),
            form: "C"
        }
    }

    getRange(){
        return {
            x: [this.x - this.r, this.x + this.r],
            y: [this.y - this.r, this.y + this.r]
        }
    }
}

class BaseOval extends BaseRect{
     constructor(units,data){
         super(units,data);
     }

     getRawData(){
         let rawData = super.getRawData();
         rawData.form = "OV";
         return rawData;
     }

     getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
         let draw = super.getDrawData(scale);
         draw.form = "OV";
         return draw;
     }
}

class BasePolygon extends BaseImage{
    x = 0;

    y = 0;

    r = 0;

    // 多边形的边数
    num = 0;

    rotate = 0;
    constructor(units,data){
        super(units);
        if(data){
            this.setRawData(data);
        }
    }

    getRawData(){
        return {
            form: "POLY",
            x: this.x,
            y: this.y,
            r: this.r,
            num: this.num,
            rotate: this.rotate
        }
    }

    setRawData(data){
        if(!super.setRawData(data)) return;
        this.x = data.x || 0;
        this.y = data.y || 0;

        this.r = data.r || 0;
        this.num = data.num || 0;
    }

    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }

        return {
            x: Math.round(this.x * scale),
            y: Math.round(this.y * - scale),
            form: "POLY",
            r: Math.round(this.r * scale),
            num: this.num,
            rotate: this.rotate
        }
    }

    getRange(){
        let range = {
            x: [this.x - this.r, this.x + this.r],
            y: [this.y = this.r, this.y + this.r]
        }
        return range;
    }
}

class BaseOctagon extends BasePolygon{
    constructor(units,data){
        data.num = 8;
        super(units,data);
    }

    setRawData(data){
        data.num = 8;
        super.setRawData(data);
    }

    getRawData(){
        return {
            x: this.x,
            y: this.y,
            rotate: this.rotate,
            form: "OC",
            r: this.r
        }
    }

    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
        return {
            x: Math.round(this.x * scale),
            y: Math.round(this.y * - scale),
            form: "OC",
            r: Math.round(this.r * scale),
            rotate: this.rotate
        }
    }
}

class BaseRoundRect extends BaseRect{

    // 圆角弧度
    r = 0;

    constructor(units,data){
        super(units);
        if(data){
            this.setRawData(data);
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.r = data.r;
    }

    getRawData(){
        let rawData = super.getDrawData(scale);
        rawData.form = "CS";
        rawData.r = this.r;

        return graphicUtil.cs2Path(rawData);
    }

    /**
     * 
     * @param {number} scale 
     * @returns {{
     *  w: number;
     *  h: number;
     *  x: number;
     *  y: number;
     *  form: string;
     *  r: number
     * }}
     */
    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
        let draw = super.getDrawData(scale);
        draw.form = "CS";
        draw.r = Math.round(this.r * scale);
        return draw;
    }
}

// 带宽度线条
class Line extends BaseLine{
    // 线宽
    lineWidth = 0;

    strokeStyle = "";

    constructor(units,data){
        super(units);

        if(data){
            this.setRawData(data);
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.lineWidth = data.width || (this.units == "mm" ? 0.127 : 0.127 * 39.37);
    }

    getRawData(){
        let originData = super.getRawData();
        originData.width = this.lineWidth;
        return originData;
    }

    getRange(){
        var big = {
            a:Math.abs(this.startY - this.endY),
            b:Math.abs(this.startX - this.endX)
        }

        big.c = Math.sqrt(big.a*big.a+big.b*big.b);

        var small = {
            a:(this.lineWidth/2)/big.c * big.a,
            b:(this.lineWidth/2)/big.c * big.b
        }
        var maxX = this.startX + small.a > this.endX + small.a ? this.startX + small.a : this.endX + small.a;
        
        var minX = this.startX - small.a < this.endX - small.a ? this.startX - small.a : this.endX - small.a;
        var maxY = this.startY + small.b > this.endY + small.b ? this.startY + small.b : this.endY + small.b;
        var minY = this.startY - small.b < this.endY - small.b ? this.startY - small.b : this.endY - small.b;

        return {
            x: [minX,maxX],
            y: [minY, maxY]
        }
    }

    getDrawData(scale){
        if(!scale && scale !== 0){
            scale = 1;
        }
        if(this.lineWidth * scale < 0.2){
            // console.log("线宽小于3")
            return [];
        }
        let drawData = super.getDrawData(scale);
        drawData.width = this.lineWidth * scale;
        return {
            id:this.id,
            layer: this.layer,
            type: this.type,
            form: this.form,
            strokeStyle:this.strokeStyle,
            data:drawData
        }
    }

    inSelect(point){

    }
}

// 封装线条
class ELine extends Line{
    layer = "st";

    constructor(units,layer,data){
        super(units,data);
        this.setLayer(layer);
    }

    setLayer(layer){
        if(!checkLayer(layer)){
            throw "传入的参数有误！"
        }
        this.layer = layer;
        this.strokeStyle = styleConfig.layer[this.layer].path.color_line;
    }
}

class EArc extends BaseArc{
    layer = "st";
    // 线宽
    lineWidth = 0;

    strokeStyle = "";

    constructor(units,layer,data){
        super(units);
        this.setLayer(layer);
        if(data){
            this.setRawData(data);
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.lineWidth = data.width || 0;
    }

    setLayer(layer){
        if(!checkLayer(layer)){
            throw "传入的参数有误！"
        }
        this.layer = layer;
        
        this.strokeStyle = styleConfig.layer[this.layer].path.color_line;
    }

    getRawData(){
        let originData = super.getRawData();
        originData.width = this.lineWidth;
        return originData;
    }

    getRange(){
        var range = super.getRange();
        range.x[0] -= this.lineWidth/2;
        range.x[1] += this.lineWidth/2;
        range.y[0] -= this.lineWidth/2;
        range.y[1] += this.lineWidth/2;
        return range;
    }

    getDrawData(scale){
        let drawData = super.getDrawData(scale);
        drawData.width = this.lineWidth * scale;
        return {
            id:this.id,
            layer: this.layer,
            type: this.type,
            form: this.form,
            strokeStyle: this.strokeStyle,
            data:drawData
        }
    }

    getCenter(){
        return {
            x : (range.x[0] + range.x[1]) / 2,
            y : (range.y[0] + range.y[1]) / 2
        }
    }
}

class ERect extends BaseRect{
    // 线宽
    lineWidth = 0;

    // 填色
    strokeStyle = "";

    // 所属层级
    layer = "";

    constructor(units,layer,rectData){
        super(units);
        this.setLayer(layer);
        this.type = "paths";
        if(rectData){
            this.setRawData(rectData);
        }
    }

    setLayer(layer){
        if(!checkLayer(layer)){
            throw "传入的参数有误！"
        }
        this.layer = layer;
        this.strokeStyle = styleConfig.layer[this.layer].path.color_line;
    }

    setRawData(rectData){
        super.setRawData(rectData);
        this.lineWidth = rectData.width || (this.units == "mm" ? 0.127 : 0.127 * 39.37);
    }

    getRawData(){
        let rect = super.getRawData();
        rect.width = this.lineWidth;
        return rect;
    }

    getDrawData(scale){
        if(!scale){
            scale = 1;
        }
        let drawRect = super.getDrawData();
        drawRect.width = this.lineWidth * scale;
        return {
            id: this.id,
            form:"S",
            type: this.type,
            layer: this.layer,
            strokeStyle: this.strokeStyle,
            data: drawRect
        }
    }
}

class Shape extends BaseImage{
    layer = "st";

    /**
     * @type {BaseLine []}
     */
    outline = [];

    /**
     * @type {BaseLine [][]}
     */
    fill = [];

    type = "shapes";

    fillStyle = "blue";

    constructor(units,layer,shapeData){
        super(units);
        this.layer = layer;
        if(shapeData){
            this.setRawData(shapeData);
        }
    }

    setRawData(shapeData){
        if(!shapeData){
            return;
        }
        let fill = [],outline = [];
        if(shapeData instanceof Array){
            outline = shapeData;
        }else{
            try {
                
                if(shapeData.fill.length &&typeof shapeData.fill.forEach == "function"){
                    fill = shapeData.fill;
                }
            } catch (error) {
                console.log(shapeData);
            }
            if(shapeData.outline.length &&typeof shapeData.outline.forEach == "function"){
                outline = shapeData.outline;
            }
        }

        outline.forEach((pathData)=>{
            this.outline.push(BasePath.create(pathData,this.units));
        });

        fill.forEach((pathData,index)=>{
            if(pathData instanceof Array){
                this.fill[index] = [];
                pathData.forEach(line=>{
                    this.fill[index].push(BasePath.create(line,this.units));
                });
            }else{
                this.fill[0].push(BasePath.create(pathData,this.units))
            }
        });
    }

    getRawData(){
        let shape = {
            outline:[],
            fill:[]
        }
        this.outline.forEach(line=>{
            shape.outline.push(line.getRawData());
        });

        this.fill.forEach((paths,index)=>{
            shape.fill[index] = [];
            paths.forEach(line=>{
                shape.fill[index].push(line.getRawData());
            });
        });

        return shape;
    }

    getDrawData(scale){
        let range = this.getDrawRange(scale);
        if(Math.abs(range.x[0] - range.x[1]) < 1 || Math.abs(range.y[0] - range.y[1]) < 1){
            return [];
        }
        let drawOutline = [],drawFill = [];
        this.outline.forEach(line=>{
            drawOutline.push(line.getDrawData(scale));
        });
        this.fill.forEach((fillItem,index)=>{
            drawFill[index] = [];
            fillItem.forEach(line=>{
                drawFill[index].push(line.getDrawData(scale))
            });
        });
        return {
            id:this.id,
            layer:this.layer,
            type: this.type,
            fillStyle: this.isTouch ? "orange" : this.fillStyle,
            alpha: 0.4,
            data:{
                outline:drawOutline,
                fill:drawFill
            }
        }
    }

    getRange(){

        var outlineRange = null;
        var fillRange = null;

        this.outline.forEach(line=>{
            let lineRange = line.getRange();
            outlineRange = compareRange(outlineRange,lineRange);
        });

        this.fill.forEach(fillItem=>{
            fillItem.forEach(line=>{
                let lineRange = line.getRange();
                fillRange = compareRange(outlineRange,lineRange);
            })
        });

        if(!outlineRange && !fillRange){
            return null;
        }

        return compareRange(outlineRange,fillRange);

        function compareRange(range,toRange){
            if(!toRange){
                return {
                    x:[
                        range.x[0],
                        range.x[1]
                    ],
                    y:[
                        range.y[0],
                        range.y[1]
                    ]
                };
            }
            if(!range){
                return {
                    x:[
                        toRange.x[0],
                        toRange.x[1]
                    ],
                    y:[
                        toRange.y[0],
                        toRange.y[1]
                    ]
                };
            }
            var compare = {
                x:[0,0],
                y:[0,0]
            }
            compare.x[0] = toRange.x[0] < range.x[0] ? toRange.x[0] : range.x[0];
            compare.x[1] = toRange.x[1] > range.x[1] ? toRange.x[1] : range.x[1];
            compare.y[0] = toRange.y[0] < range.y[0] ? toRange.y[0] : range.y[0];
            compare.y[1] = toRange.y[1] > range.y[1] ? toRange.y[1] : range.y[1];
            return compare;
        }
    }

    getCenter(){
        var xSum = 0, ySum = 0;
        this.outline.forEach(line=>{
            let center = line.getCenter();
            xSum += center.x;
            ySum += center.y;
        });
        return {
            x: xSum / this.outline.length,
            y: ySum / this.outline.length
        }
    }
}

class EShape extends Shape{
    constructor(units,layer,shapeData){
        if(!checkLayer(layer)){
            throw "传入的参数有误！"
        }
        super(units,layer,shapeData);
        
        this.fillStyle = styleConfig.layer[this.layer].shape.color_fill;
    }
}

class Pin extends BaseImage{
    /**
     * @type {EPad}
     */
    pad = null;

    x = 0;

    y = 0;

    rotate = 0;

    constructor(units,data){
        super(units);
        if(data){
            this.setRawData(data);
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.x = data.x;
        this.y = data.y;
        this.rotate = data.rotate;
    }

    getRawData(){
        return {
            x: this.x,
            y: this.y,
            rotate: this.rotate
        }
    }

    getRange(){
        let padRange = this.pad.getRange();

        if(padRange.x[0] == padRange.x[1]){
            console.error("pad计算有误",this.pad,padRange)
        }

        padRange.x[0] += this.x;
        padRange.x[1] += this.x;
        padRange.y[0] += this.y;
        padRange.y[1] += this.y;

        if(this.rotate){
            padRange = graphicUtil.rotateRange(padRange,this.rotate,{x:this.x,y:this.y});
        }

        return padRange;
    }

    getDrawData(scale,viewStatus){
        if(!scale && scale !== 0){
            scale = 1;
        }
        
        //判断是否太小了
        let range = this.getDrawRange(scale);
        let w = (range.x[1] - range.x[0]) / 2;
        let h = (range.y[1] - range.y[0]) / 2;
        if(w <=1 || h <= 1){
            return [];
        }
        let x = this.x * scale, y = this.y * - scale, rotate = this.rotate, num = this.number;
        let drawPads = this.pad.getDrawData(scale,viewStatus);
        let draw = [];

        drawPads.forEach(drawPad=>{
            drawPad.data.x = x;
            drawPad.data.y = y;
            drawPad.data.pRotate = rotate;
            drawPad.pin_num = num;
            drawPad.type = "pins";
            drawPad.id = this.id;
            draw.push(drawPad);
        });
        let pinPriority = {b:5,bs_t:3,bs_b:1,bp_t:4,bp_b:2,t:15,ts_t:13,ts_b:11,tp_t:14,tp_b:12,i:10,is_t:8,is_b:6,ip_t:9,ip_b:7,drill:16}
        //"b","bs_t","bs_b","bp_t","bp_b","t","ts_t","ts_b","tp_t","tp_b","i","is_t","is_b","ip_t","ip_b","drill"
        drawPads = drawPads.sort(function(p1,p2){
            return pinPriority[p1.layer] - pinPriority[p2.layer];
        });
        return draw;
    }
}

// 引脚
class EPin extends Pin{

    number = "";

    type = "pins";

    constructor(units,data){
        super(units);
        if(data){
            this.setRawData(data);
        }
    }

    getRawData(){
        return {
            x: this.x,
            y: this.y,
            rotate: this.rotate,
            pin_id: this.number,
            pin_padid: this.pad.id
        }
    }

    setRawData(data){
        super.setRawData(data);
        this.number = data.pin_id;
    }

    setPad(pad){
        if(!(pad instanceof EPad)){
            throw "TypeError: 传入的Pad数据有误，需要一个EPad实例！";
        }
        this.pad = pad;
    }

    getDrawData(scale,viewStatus){
        let drawData = super.getDrawData(scale,viewStatus);
        drawData.forEach(pin=>{
            pin.pin_num = this.number;
        });
        // console.log(drawData)
        return drawData;
    }

    static createPin(option){
        let {units,x,y,rotate,number,pad} = option;
        let ePin = new EPin(units,{x,y,rotate,pin_id:number});
        if(pad){
            ePin.setPad(pad);
        }
    }
}

class EPad extends BaseImage{
    type = "pad";

    data = {
        b: null,
        bs_t: null,
        bs_b: null,
        bp_t: null,
        bp_b: null,
        t: null,
        ts_t: null,
        ts_b: null,
        tp_t: null,
        tp_b: null,
        i: null,
        is_t: null,
        is_b: null,
        ip_t: null,
        ip_b: null,
        drill: []
    }

    kind = "smt"

    constructor(units,data){
        super(units);
        if(data){
            this.setRawData(data);
        }
    }

    getRawData(){
        let padOutLayer = ["b","t","i"];
        let padInLayers = {
            b:["b","bs_t","bs_b","bp_t","bp_b"],
            t:["t","ts_t","ts_b","tp_t","tp_b"],
            i:["i","is_t","is_b","ip_t","ip_b"]
        };

        let pad = {
            id: this.id,
            kind: this.kind,
            drill:[]
        };

        padOutLayer.forEach(oLayer=>{
            pad[oLayer] = {};
            padInLayers[oLayer].forEach(mLayer=>{
                if(this.data[mLayer]){
                    pad[oLayer][mLayer] = this.data[mLayer].getRawData();
                }else{
                    pad[oLayer][mLayer] = {};
                }
            });
        });

        this.data.drill.forEach(drillIns=>{
            pad.drill.push(drillIns.getRawData());
        });
        return pad;
    }

    setRawData(data){
        super.setRawData(data);

        this.kind = data.kind;

        let padBigLayer = ["b","t","i","drill"];
        let padSmallLayer = {b:["b","bs_t","bs_b","bp_t","bp_b"],t:["t","ts_t","ts_b","tp_t","tp_b"],i:["i","is_t","is_b","ip_t","ip_b"]};

        padBigLayer.forEach(bigLayer=>{
            if(bigLayer !== "drill"){
                padSmallLayer[bigLayer].forEach(sLayer=>{
                    if(data[bigLayer][sLayer] && data[bigLayer][sLayer].form){
                        this.data[sLayer] = new PadLayer(this.units,sLayer,data[bigLayer][sLayer]);
                    }
                })
            }else{
                if(data[bigLayer] instanceof Array){
                    data[bigLayer].forEach(layerData=>{
                        let drillData = {
                            r: layerData.diameter / 2,
                            skewing_x:layerData.offset.x,
                            skewing_y:layerData.offset.y,
                            w: layerData.hole.w,
                            h: layerData.hole.h,
                            form: layerData.hole.form,
                            rotate: layerData.hole.rotate
                        }
                        this.data[bigLayer].push(new PadLayer(this.units,bigLayer,drillData));
                    });
                }
            }
        });
    }

    getDrawData(scale,viewStatus){
        let padSmallLayer = ["b","bs_t","bs_b","bp_t","bp_b","t","ts_t","ts_b","tp_t","tp_b","i","is_t","is_b","ip_t","ip_b","drill"];
        let draw = [];
        padSmallLayer.forEach(layer=>{
            if(!viewStatus[layer]){
                return;
            }
            let padLayer = this.data[layer];
            if(layer !== "drill"){
                if(padLayer && padLayer.graphic){
                    let drawData = padLayer.getDrawData(scale);
                    draw.push(drawData);
                }
            }else{
                padLayer.forEach(dirll=>{
                    let drawData = dirll.getDrawData(scale);
                    draw.push(drawData);
                });
            }
        });
        return draw;
    }

    getRange(){
        let padLayer = ["b","bs_t","bs_b","bp_t","bp_b","t","ts_t","ts_b","tp_t","tp_b","i","is_t","is_b","ip_t","ip_b"];
        let range = null;
        padLayer.forEach(layer=>{
            if(this.data[layer]){
                range = graphicUtil.compareRange(range,this.data[layer].getRange());
            }
        });
        if(this.data.drill){
            this.data.drill.forEach(dirll=>{
                range = graphicUtil.compareRange(range,dirll.getRange());
            })
        }
        return range;
    }

    /**
     * 
     * @param {{
     * units: string,
     * form: string,
     * type: string,
     * formOption:{r:number,w:number,h:number,num:number,offset:{x:number,y:number}},
     * drillOption:{form:string,r:number,w:number,h:number,offset:{x:number,y:number}}
     * }} config 
     * @returns 
     */
    static createPad(config){
        let typeLayer = {
            via:["b","bs_t","bs_b","t","ts_t","ts_b","i","is_t","is_b","drill"],
            hole:["drill"],
            smt:["t","ts_t","ts_b","tp_t","tp_b"]
        };

        let {units,form,type,formOption,drillOption} = config;

        if(!r && !w && !h){
            return false;
        }

        let layers = typeLayer[type];

        let pad = new EPad(units);

        pad.kind = type;

        drillForm = config.drillForm || "C";

        let padLayerDate = {
            form,
            r:formOption.r,
            w:formOption.w,
            h:formOption.h,
            num:formOption.num,
            skewing_x: formOption.offset.x,
            skewing_y: formOption.offset.y
        }

        let solderResist = {
            form,
            r: units === "mm"?formOption.r+0.1:formOption.r+4,
            w: units === "mm"?formOption.w+0.1:formOption.w+4,
            h: units === "mm"?formOption.h+0.1:formOption.h+4,
            num,
            skewing_x: formOption.offset.x,
            skewing_y: formOption.offset.y
        }

        let drillDate = {
            form: drillOption.form,
            r: drillOption.r,
            w: drillOption.w,
            h: drillOption.h,
            skewing_x: drillOption.offset.x,
            skewing_y: drillOption.offset.y
        }

        layers.forEach(layer=>{
            if(layer !== "drill"){
                if(layer.slice(1) == "s_t" || layer.slice(1) == "s_b"){
                    
                    pad.data[layer] = new PadLayer(units,layer,padLayerDate);
                }else{

                    pad.data[layer] = new PadLayer(units,layer,solderResist);
                }
            }else{
                pad.data[layer].push(new PadLayer(units,layer,drillDate))
            }
        });

        return pad;
    }
}

class PadLayer{
    /**@type {BaseImage} */
    graphic = null;

    fillStyle = "";

    layer = "";

    units = "";

    offset = {
        x: 0,
        y: 0
    }

    rotate = 0;

    constructor(units,layer,graphic){
        this.units = units;
        this.layer = layer;
        this.fillStyle = styleConfig.pin.color[layer];
        if(graphic){
            this.setGraphicData(graphic);
        }
    }

    setGraphicData(data){
        let nameConversion = {CIRCLE:"C",CIRCLE_DRILL:"C",SQUARE:"S",RECTANGLE:"S",RECTANGLE_DRILL:"S",SQUARE_DRILL:"S",OCTAGON:"OC",HOLE_OCTAGON:"OC",OCTAGON_DRILL:"OC",OBLONG_Y:"OV",OVAL:"OV",OBLONG_X:"OV",HOLE_OVAL:"OV",OVAL_DRILL:"OV",OVAL_SLOT:"OV"};
        let form = nameConversion[data.form.toUpperCase()] || data.form.toUpperCase();
        let baseImage = null;
        if(form == "C"){
            baseImage =  new BaseCircle(this.units,data);
        }
        if(form == "S"){
            baseImage = new BaseRect(this.units,data);
        }
        if(form == "CS"){
            baseImage = new BaseRoundRect(this.units,data);
        }
        if(form == "OV"){
            baseImage = new BaseOval(this.units,data);
        }
        if(form == "PATH"){
            baseImage = new BasePath(this.units,data.path);
        }
        if(form == "POLY"){
            baseImage = new BasePolygon(this.units,data);
        }
        this.graphic = baseImage;
        this.offset.x = data.skewing_x || 0;
        this.offset.y = data.skewing_y || 0;
        this.rotate = data.rotate || 0;
    }

    getDrawData(scale){
        if(!scale){
            scale = 1;
        }
        if(this.graphic instanceof BasePath){
            let layerDraw = {
                layer: this.layer,
                fillStyle: this.fillStyle,
                data:{
                    path:this.graphic.getDrawData(scale),
                    skewing_x: this.offset.x * scale,
                    skewing_y: -this.offset.y * scale,
                    rotate: this.rotate,
                    form: "PATH"
                }
            }
            return layerDraw;
        }else{
            let drawData = this.graphic.getDrawData(scale);
            drawData.skewing_x = this.offset.x * scale;
            drawData.skewing_y = - this.offset.y * scale;
            drawData.rotate = this.rotate;
            let layerDraw = {
                fillStyle: this.fillStyle,
                layer:this.layer,
                data:drawData
            }
            return layerDraw;
        }
    }

    getRange(){
        let range = this.graphic.getRange();
        range.x[0] += this.offset.x;
        range.x[1] += this.offset.x;
        range.y[0] += this.offset.y;
        range.y[1] += this.offset.y;
        if(this.rotate){
            range = graphicUtil.rotateRange(range,this.range);
        }
        return range;
    }

    getRawData(){
        let layerFormTrans = {C:"CIRCLE",S:"RECTANGLE",OC:"OCTAGON",OV:"OBLONG"};
        let drillFormTrans = {C:"CIRCLE_DRILL",S:"RECTANGLE_SLOT",OC:"OCTAGON_DRILL",OV:"OVAL_SLOT"};

        let layerData = this.graphic.getRawData();

        layerData.skewing_x = this.offset.x;
        layerData.skewing_y = this.offset.y;
        layerData.rotate = this.rotate;
        if(this.layer !== "drill"){
            layerData.form = layerFormTrans[layerData.form] || layerData.form;
            return layerData
        }else{
            let originDrill = {
                hole: {
                    rotate: layerData.rotate,
                    form: drillFormTrans[layerData.form] || layerData.form,
                    w: layerData.w,
                    h: layerData.h
                },
                keepout: "nil",
                graphic: {
                    w: layerData.w,
                    name: "CROSS",
                    h: layerData.h
                },
                diameter: layerData.w,
                offset: {
                    x: layerData.skewing_x,
                    y: layerData.skewing_y
                },
                plate: "nil",
                tolerance: {
                    x: 0,
                    y: 0
                },
                uvia: "nil",
                start_end_layer: {
                    end_layer: "ETCH/BOTTOM",
                    st_layer: "ETCH/TOP"
                }
            }
            if(layerData.form == "C"){
                originDrill.graphic.name = "Null";
            }else if(layerData.form == "OV"){
                originDrill.graphic.name = "OblongX";
            }else if(layerData.form == "S"){
                originDrill.graphic.name = "Rectangle";
            }
            return originDrill;
        }
    }
}

export default Encapsulation;

export {
    Encapsulation,
    EPin,
    EPad,
    EText,
    ELine,
    EArc,
    ERect,
    EShape
}